/*************************************************************************************
**																					**
**	radioapi.c			Sx1272 RFIC										**
** 																					**
**************************************************************************************
**																					**
** Written By:	Steve Montgomery													**
**				Digital Six Laboratories LLC										**
** (c)2012,2013,2014 Digital Six Labs, All rights reserved							**
**																					**
**************************************************************************************/
// OpenRF™ Protocol Platform
// Open Source - MIT License
//
// Configuration Defines
//
// RADIOMODE_LORA - Sets radio mode for LORA
//
// Revision History
//
// Revision		Date	Revisor		Description
// ===================================================================================
// ===================================================================================
#include "radioapi.h"

U8 state=0;
/// internal data structure for the RadioAPI

UU32 _macAddress;
UU32 _networkId;

U8 _rxHopIndex;
U8 _txHopIndex;
U8 _gausianEnabled;
tOperatingModes _operatingMode;
tRadioStates _radioMode;
U8 _rxBuffer[64];
U8 _rxLen;
U8 *_sdu;

U16 _cntr;
U16 _cntrMax=0;
U16 _timers[MAXTIMERS];
U8 _radioType;
U8 _registers[0x80];
U8 _tableNumber;
U8 _quickScan=0;
U8 _scanChannel;
U8 _scanIncrement;
U16 _rxTimeout;

struct
{
	U32 crcErrors;
	U32 validPackets;
	U32 cadDetect;
	U32 rxStart;
} _radioStatistics;

//**** Timer assignments
#define RXTIMER 0

#define WriteCHARSPI WriteCharSPI
#define ReadCHARSPI ReadCharSPI
#define PERFTIMER 3
// returns zero if the change is made, one if the mode times out
U8 WaitForModeChange(U8 mode)
{
	U16 timeOut;
	U8 val;

	timeOut = kModeChangeTimeout;

	val= ReadCHARSPI(RegOpMode);
	while(timeOut && (val!=mode))
	{
		val= ReadCHARSPI(RegOpMode);
		timeOut--;
	}

	if(timeOut)
		return 0;
	else
		return 1;

}
void ReadRegs()
{
	int i;
	for(i=0x1;i<0x80;i++)
		_registers[i] = ReadCHARSPI(i);
	i=9;
}
void ClearFIFO()
{
	WriteCHARSPI(RegIrqFlags2,0x10);
}

#ifdef RADIOMODE_FSK
void HandleReceivedPacket()
{
	U8 *sdu;
	U8 x,y;
	U8 length, orgLength;


	UU32 sourceMACAddress, destMACAddress;
	U8 packetType;
	WriteCHARSPI(RegOpMode,0x00);
	WaitForModeChange(0);

	int i;
	length = ReadCHARSPI(RegFifo);
	i=0;
	for(i=0;i<length;i++)
	{
		x=ReadCHARSPI(RegFifo);
		_rxBuffer[i] = x;
	}
	sdu = &(_rxBuffer[0]);
	NotifyRadioPacketReceived(length, sdu, 0);

	// always leave with an empty FIFO
	ClearFIFO();
}
#endif
// ***********************************************************************************
// *** Interrupt Handlers ***
// These are public functions exposed by radioapi and used by microapi to notify
// when an interrupt happens.  These execute in the ISR context.  Use normal
// programming precautions.

// called by microcontroller for io based interrupts
void HandleInterrupt(U8 intType)
{

	U8 idata isr1;
	U8 idata isr2,i,temp,pktRssi;
	S8 calcRssi,pktSnr;

	// Tx-> PktSent
	// Rx-> CrcOk
#ifdef RADIOMODE_LORA
	if(intType == kInterruptP0)
	{
		switch(_operatingMode)
		{
		case kSleepMode:
		case kStandbyMode:
		case kFSTXMode:
		case kFSRXMode:
					// we should never get here.
			break;
		case kTransmitMode:
			// TxDone
			NotifyRadioPacketSent();
			WriteCHARSPI(RegLoraIrqFlags,0x08);
			RadioSleepMode();
			break;
		case kRxContinuousMode:
			// RxDone
			// in here the packet should be done

			WriteCHARSPI(RegLoraIrqFlags,0x40);
			isr1 = ReadCHARSPI(RegLoraIrqFlags);
			if(isr1 & 0x20)
			{
				// todo : we need to decide how we will handle errors in continuous mode.  For now we ignore them and move on.
				// in here, we have a CRC error
				_radioStatistics.crcErrors++;
				WriteCHARSPI(RegLoraIrqFlags,0x20);
				NotifyRadioReceiveError();
			}
			else
			{
				_radioStatistics.validPackets++;
				pktSnr = ReadCHARSPI(RegLoraPktSnrValue);
				pktRssi = ReadCHARSPI(RegLoraPktRssiValue);
				if(pktSnr & 0x80)
				{
					pktSnr = ((~pktSnr + 1)&0xff)>>2;
					pktSnr = -pktSnr;
				}
				else
				{
					pktSnr = (~pktSnr &0xff)>>2;
				}
				calcRssi = pktRssi;
				calcRssi += pktRssi>>4;
				calcRssi -= 139;
				if(pktSnr<0)
					calcRssi += pktSnr;
				_rxLen = ReadCHARSPI(RegLoraRxNbBytes);
				for(i=0;i<_rxLen;i++)
					_rxBuffer[i] = ReadCHARSPI(RegFifo);
				NotifyRadioPacketReceived(_rxLen, _rxBuffer, calcRssi);
			}
			ReadRegs();
			break;
		case kRxSingleMode:
			// RxDone
			// in here the packet should be done
			if(pinRadioDIO3)
			{
				// in here, we have a CRC error
				_radioStatistics.crcErrors++;
				NotifyRadioReceiveError();
			}
			else
			{
				_radioStatistics.validPackets++;
				_rxLen = ReadCHARSPI(RegLoraRxNbBytes);
				for(i=0;i<_rxLen;i++)
					_rxBuffer[i] = ReadCHARSPI(RegFifo);
				NotifyRadioPacketReceived(_rxLen, _rxBuffer,pktRssi);
				RadioSleepMode();
			}
			WriteCHARSPI(RegLoraIrqFlags,0xff);
			break;
		case kCADMode:
			// CADDone

			WriteCHARSPI(RegLoraIrqFlags,0x04);
			if(pinRadioDIO1)
			{
				WriteCHARSPI(RegLoraIrqFlags,0x01);
				_radioStatistics.cadDetect++;
				// todo: determine if this is really needed 8-11-2014
				WriteCHARSPI(RegLoraIrqFlagsMask,0x00);
				// when a preamble is detected, it is thrown away if it lasts longer than this setting.  Right now, the transmitter is set to 1200 symbols, so we will wait 0x4ff max.
				WriteCHARSPI(RegLoraPreambleMsb,3);
				WriteCHARSPI(RegLoraPreambleLsb,60);
				// the RX timeout will still occur.  we need to clear it when it fires, but that is all.
				WriteCHARSPI(RegLoraSymbTimeoutLsb,0xff);
				WriteCHARSPI(RegLoraIrqFlags,0x01);
				WriteCHARSPI(RegDioMapping1,0x02);
				WriteCHARSPI(RegLoraFifoAddrPtr,ReadCHARSPI(RegLoraFifoRxBaseAddr));
				WriteCHARSPI(RegOpMode, 0x06);
				_operatingMode = kRxSingleMode;
			}
			else
			{
				// todo: is this the right way to do this? What is the proper response when a CAD detect fails?  We need some kind of notification so that
				// MAC will terminate listen state.
				NotifyRadioReceiveError();
			}
			break;
		}
	}
	else if(intType == kInterruptP1)
	{
		switch(_operatingMode)
		{
		case kSleepMode:
		case kStandbyMode:
		case kFSTXMode:
		case kFSRXMode:
		case kTransmitMode:
					// we should never get here.
			break;
		case kRxContinuousMode:
			// RX Timeout
			WriteCHARSPI(RegLoraIrqFlags,0x80);
			NotifyRadioReceiveError();
			break;
		case kRxSingleMode:
			// RxTimeout - Just clear it and let it go.
			WriteCHARSPI(RegLoraIrqFlags,0x80);
			break;
		case kCADMode:
			// CADDetected
			// should not get here.  this should be handled in INTP0 handler.
			break;
		}
	}
	else if(intType == kInterruptP2)
	{
		switch(_operatingMode)
		{
		case kSleepMode:
		case kStandbyMode:
		case kFSTXMode:
		case kFSRXMode:
					// we should never get here.
			break;
		case kTransmitMode:
			// FHSS Change
			break;
		case kRxContinuousMode:
			// FHSS Change
			break;
		case kRxSingleMode:
			// FHSS Change
			break;
		case kCADMode:
			// FHSS Change
			break;
		}
	}
	else if(intType == kInterruptP3)
	{
		switch(_operatingMode)
		{
		case kSleepMode:
		case kStandbyMode:
		case kFSTXMode:
		case kFSRXMode:
		case kTransmitMode:
		case kCADMode:
					// we should never get here.
			break;
		case kRxContinuousMode:
		case kRxSingleMode:
			// Payload CRC Error - should be handled in RXDONE interrupt handler
			break;
		}
	}
	else if(intType == kInterruptP4)
	{
		switch(_operatingMode)
		{
		case kSleepMode:
		case kStandbyMode:
		case kFSTXMode:
		case kFSRXMode:
			// we should never get here.
			break;
		case kTransmitMode:
		case kCADMode:
		case kRxContinuousMode:
		case kRxSingleMode:
			// PLL Lock
			break;
		}
	}
	else if(intType == kInterruptP5)
	{

		switch(_operatingMode)
		{
		case kSleepMode:
		case kStandbyMode:
		case kFSTXMode:
		case kFSRXMode:
			// we should never get here.
			break;
		case kTransmitMode:
		case kCADMode:
		case kRxContinuousMode:
		case kRxSingleMode:
			// ModeReady
			break;
		}
	}
#endif
#ifdef RADIOMODE_FSK
	if(intType==kInterruptP0)
	{
		isr1 = ReadCHARSPI(RegIrqFlags1);
		isr2 = ReadCHARSPI(RegIrqFlags2);

		switch(_radioMode)
		{
			case kIdleRxMode:
			case kRxMode:
				if(isr2 & 0x04)
				{
					// received a packet
					HandleReceivedPacket();
					StandbyMode();
				}

				//else // if(isr1 & EZRADIOPRO_ICRCERROR)
					//NotifyRadioReceiveError();
				break;
			case kTxMode:
				// process "packet sent" interrupt
				if(isr2 & 0x08)
				{
					//NotifyRadioPacketSent();
					StandbyMode();
				}
				else
				{
					ClearFIFO();
					//NotifyRadioPacketSendError();
				}
				break;
		}
	}
#endif
}


// called by microcontroller every 1mSec.  Timeouts should be tied to this
void Handle1MsInterrupt()
{
	int i;
	for(i=0;i<MAXTIMERS;i++)
		_timers[i]++;
	NotifyRadio1MilliSecond();
}
// called by microcontroller every second.  This is used to drive an internal clock
void Handle1SecInterrupt()
{
	NotifyRadio1Second();
}

// ***********************************************************************************
// *** Internal Functions ***
void ClearTimer(U8 timer)
{
	DI();
	_timers[timer] = 0;
	EI();
}

// ***********************************************************************************
// *** Public API ***


void QueueTransmitPacket(U8 length, U8 xdata *txBuffer)
{
		U8 sduLength,i,a,b;

		sduLength = length;
		// Setup DIO pins for transmit  mode
		// dio0 = TXDONE, dio1 = NA, dio2=FHSSCHANGE, dio3=NA, dio4=PLLLOCK, dio5=MODERDY, CLKOUT = off
		WriteCHARSPI(RegDioMapping1, 0x73);
		WriteCHARSPI(RegDioMapping2, 0x40);
		WriteCHARSPI(RegLoraIrqFlagsMask,0xf7);
#ifdef RADIOMODE_LORA
		WriteCHARSPI(RegLoraFifoAddrPtr,0x80);
		WriteCHARSPI(RegLoraPayloadLength,length);
		//WriteCHARSPI(RegLoraPreambleLsb,0xaf);
#endif
		// the first byte must be the length of the packet, but the length count should not include this count.  So we add 5 to account for overhead instead of 6.
		//WriteCHARSPI(RegFifo,length);
		for(i=0;i<sduLength;i++)
			WriteCHARSPI(RegFifo,*(txBuffer++));
}

void TransmitQueuedPacket(
 blocking)
{
	U8 retVal,i;
#ifdef RADIOMODE_LORA

	if(blocking == kBlockingCall)
	{
		// do a complete transmit cycle and exit
		WriteCHARSPI(RegOpMode, 0x03);
		while( !pinRadioDIO0);
		WriteCHARSPI(RegLoraIrqFlags,0x08);
	}
	else if(blocking == kEventDriven)
	{
		WriteCHARSPI(RegOpMode,0x03);
		_operatingMode = kTransmitMode;
		// todo: For some reason, we have to do a readSPI after a mode change to TX to ensure that the chip operates properly.  Verify the SPI setup to make sure we have the right polarity and clock phase settings.
		ReadCHARSPI(RegOpMode);
		EnableIntP0();
	//	for(i=0x1;i<0x2;i++)
	//		_registers[i] = ReadCHARSPI(i);
	}
#endif
}

/// MethodResult SendPacket(U8 length, U8 *SDU)
///
/// Parameters:
/// destAddress, unsigned long, destination for this message
/// packetType, PacketTypes, type of packet (uniack, uninoack, multi)
/// length, unsigned char, length of SDU
/// SDU, unsigned char *, service data unit to send
///
/// Description:
/// Calling this function will configure the radio to transmit a packet, load the FIFO
/// and packet header information, and start the packet transmission.  Once the process is
/// started, this function will return.  When the packet has been successfully sent,
/// RadioNotifyTxPacketComplete() will be called.  If an error occurs sending te packet,
/// RadioNotifyTxPacketError() will be called.  If the packet type is uniack, the transmit
/// complete notification happens after an acknoweldgement is received.  If the packet type
/// is not uniack, the transmit complete notification will happen once the transmission
/// finishes.
///
/// Returns:
/// kSuccess
U8 RadioSendPacket(U8 length, U8 *txBuffer, tBlockingModes blockMode)
{
	DisableInterrupts;
	QueueTransmitPacket(length,txBuffer);
	TransmitQueuedPacket(blockMode);
	EnableInterrupts;
	return 1;
}
U8 RadioSetReceiveTimeout(U16 to)
{
	_rxTimeout = to;
	return 1;
}
U8 RadioReceivePacket(tReceiveModes rxMode)
{
	U8 temp,rxDone,i,pinval,rssi, fadp, ftxb,frxb,frxc,pktRssi,snr,mc1, mc2,ms;
		U16 cadtime,t1,t2,t3,t4,t5,t6,t7;

		UU32 meterId, reading, mac;

	#ifdef RADIOMODE_LORA
		_radioStatistics.rxStart++;
		/*
		if(rxMode == kBlockingCADSingle)
		{
			ClearTimer(PERFTIMER);
			// TODO: ListenForPacket - LoraMode

			// If we are in LoRa mode, then we will enter CAD and listen for a packet.  Once CAD is done, we will test whether
			// a packet is coming in.  If so, we will start the receive process.  If not, we will go back to sleep (standby) mode.
			// This call is not blocking.  It should setup CAD and then return.
			// Setup DIO pins for CAD mode
			// dio0 = CADDone, dio1 = CadDet, dio2=FHSS, dio3=CADDONE, dio4=CadDet, dio5=ModeReady, CLKOUT = off
			WriteCHARSPI(RegDioMapping1, 0xa3);
			WriteCHARSPI(RegDioMapping2, 0x40);
			// set mode to CAD
			WriteCHARSPI(RegOpMode,kCADMode);
			temp = ReadCHARSPI(RegLoraIrqFlags);
			ClearTimer(RXTIMER);
			pinval=pinRadioDIO0;
			while(!(pinRadioDIO0) && _timers[RXTIMER]<25)
				temp = pinRadioDIO0;
			temp = ReadCHARSPI(RegLoraIrqFlags);
			WriteCHARSPI(RegLoraIrqFlags,0x04);
			rssi = ReadCHARSPI(RegLoraRssiValue);
			// for some reason, we have to allow CAD DET some time to go active.  Tried 1 and didn't work.  Seems to work great at 5
			while(_timers[PERFTIMER]<15);
			if(pinval)
				temp++;
			if(pinRadioDIO1)
			{
				// todo: determine if this is really needed 8-11-2014
				WriteCHARSPI(RegLoraIrqFlagsMask,0x00);
				// when a preamble is detected, it is thrown away if it lasts longer than this setting.  Right now, the transmitter is set to 1200 symbols, so we will wait 0x4ff max.
				WriteCHARSPI(RegLoraPreambleMsb,3);
				WriteCHARSPI(RegLoraPreambleLsb,60);
				// the RX timeout will still occur.  we need to clear it when it fires, but that is all.
				WriteCHARSPI(RegLoraSymbTimeoutLsb,0xff);

				mc2 = ReadCHARSPI(RegLoraModemConfig2);
				WriteCHARSPI(RegLoraModemConfig2,mc2 |0x02);
				WriteCHARSPI(RegLoraIrqFlags,0x01);

				WriteCHARSPI(RegDioMapping1,0x02);

				frxb = ReadCHARSPI(RegLoraFifoRxBaseAddr);
				WriteCHARSPI(RegLoraFifoAddrPtr,frxb);
				WriteCHARSPI(RegOpMode, 0x06);
				ClearTimer(RXTIMER);
				rxDone=0;
				// we will loop until we timeout or we receive a packet
				while(_timers[RXTIMER]<_rxTimeout && !rxDone)
				{
					temp = ReadCHARSPI(RegLoraIrqFlags);
					if(pinRadioDIO1)
					{
						// the RX timed out, so clear the IRQ and carry on
						WriteCHARSPI(RegLoraIrqFlags,0x80);

						//NotifyRadioReceiveError();
						//rxDone=1;
					}
					else if(pinRadioDIO0)
					{
						// in here the packet should be done
						if(pinRadioDIO3)
						{
							// in here, we have a CRC error
							NotifyRadioReceiveError();
							rxDone=1;
						}
						else
						{
							frxc = ReadCHARSPI(RegLoraFifoRxCurrentAddr);
							WriteCHARSPI(RegLoraFifoAddrPtr,frxc);

							_rxLen = ReadCHARSPI(RegLoraRxNbBytes);
							for(i=0;i<_rxLen;i++)
								_rxBuffer[i] = ReadCHARSPI(RegFifo);
							pktRssi = ReadCHARSPI(RegLoraPktRssiValue);
							snr = ReadCHARSPI(RegLoraPktSnrValue);
							mc1 = ReadCHARSPI(RegLoraModemConfig1);
							mc2 = ReadCHARSPI(RegLoraModemConfig2);
							ms = ReadCHARSPI(RegLoraModemStat);
							NotifyRadioPacketReceived(_rxLen, _rxBuffer,pktRssi);
							rxDone=1;
						}
						WriteCHARSPI(RegLoraIrqFlags,0xff);
					}
					else if(temp&0x10)
						WriteCHARSPI(RegLoraIrqFlags,0x10);
				}

				if(!rxDone)
					t1=_timers[PERFTIMER];

			}
			else
			{
			}
			t5=_timers[PERFTIMER];
			RadioStandbyMode();

			t6=_timers[PERFTIMER];
			if(!rxDone)
				t1=_timers[PERFTIMER];
			ClearFIFO();

		}
		else
		*/if(rxMode == kEventingCADSingle)
		{
			_operatingMode = kCADMode;
			WriteCHARSPI(RegDioMapping1, 0xa3);
			WriteCHARSPI(RegDioMapping2, 0x40);
			EnableIntP0();
			EnableIntP1();
			// we need to enable CAD mode.  Then, we will get a CAD done interrupt on INTP0
			WriteCHARSPI(RegOpMode,kCADMode);
			temp = ReadCHARSPI(RegLoraIrqFlags);
		}
		/*
		else if(rxMode==kBlockingNoCADContinuous)
		{
			WriteCHARSPI(RegLoraIrqFlagsMask,0x1f);
			WriteCHARSPI(RegLoraFifoAddrPtr,0x00);
			// DIO0 = RXDONE, DIO1 = RXTO, DIO2=FHSS, DIO3 = PayloadCRCError
			WriteCHARSPI(RegDioMapping1, 0x02);
			WriteCHARSPI(RegDioMapping2, 0x40);
			//WriteCHARSPI(RegLoraIrqFlagsMask,0x00);
			// when a preamble is detected, it is thrown away if it lasts longer than this setting.  Right now, the transmitter is set to 0xAF symbols, so we will wait 0xff max.
			WriteCHARSPI(RegLoraPreambleMsb,0x00);
			WriteCHARSPI(RegLoraPreambleLsb,0xff);
			// the RX timeout will still occur.  we need to clear it when it fires, but that is all.
			WriteCHARSPI(RegLoraSymbTimeoutLsb,0xff);

			// Start continuous RX mode
			WriteCHARSPI(RegOpMode,0x05);

			ClearTimer(RXTIMER);
			rxDone=0;
			// we will loop until we timeout, receiving as many packets as we can
			while(1)//_timers[RXTIMER]<_rxTimeout)
			{
				ms = ReadCHARSPI(RegLoraModemStat);
				temp = ReadCHARSPI(RegLoraIrqFlags);
				if(temp&0x80)
				{
					// the RX timed out, so clear the IRQ and carry on
					WriteCHARSPI(RegLoraIrqFlags,0x80);

					NotifyRadioReceiveError();
				}
				else if(temp&0x40)
				{
					// in here the packet should be done
					if(temp&0x20)
					{
						// in here, we have a CRC error
						NotifyRadioReceiveError();
					}
					else
					{
						_rxLen = ReadCHARSPI(RegLoraRxNbBytes);
						for(i=0;i<_rxLen;i++)
							_rxBuffer[i] = ReadCHARSPI(RegFifo);
						NotifyRadioPacketReceived(_rxLen, _rxBuffer, ReadCHARSPI(RegLoraPktRssiValue));

						temp = ReadCHARSPI(RegLoraFifoRxCurrentAddr);
						WriteCHARSPI(RegLoraFifoAddrPtr,temp);
					}
					WriteCHARSPI(RegLoraIrqFlags,0xff);
				}
				else if(temp&0x10)
					WriteCHARSPI(RegLoraIrqFlags,0x10);
			}
			//ReadRegs();
			RadioStandbyMode();
		}
		else
		*/if(rxMode == kEventingNoCADContinuous)
		{
			_operatingMode = kRxContinuousMode;
			WriteCHARSPI(RegLoraFifoAddrPtr,0x00);
			// DIO0 = RXDONE, DIO1 = RXTO, DIO2=FHSS, DIO3 = PayloadCRCError
			WriteCHARSPI(RegDioMapping1, 0x00);
			//WriteCHARSPI(RegDioMapping2, 0x40);
			WriteCHARSPI(RegLoraIrqFlagsMask,0x1f);
			// when a preamble is detected, it is thrown away if it lasts longer than this setting.  Right now, the transmitter is set to 0xAF symbols, so we will wait 0xff max.
			WriteCHARSPI(RegLoraPreambleMsb,0x00);
			WriteCHARSPI(RegLoraPreambleLsb,0xff);
			// the RX timeout will still occur.  we need to clear it when it fires, but that is all.
			WriteCHARSPI(RegLoraSymbTimeoutLsb,0xff);
			EnableIntP0();
			EnableIntP1();
			// Start continuous RX mode
			WriteCHARSPI(RegOpMode,0x05);
			temp = ReadCHARSPI(RegLoraIrqFlags);
		}
		return 1;
	#endif

}

U8 RadioInitializeAPI()
{
	U8 i;
	ResetRadio();
	// Make sure radio is in sleep mode, without LoRa
	WriteCHARSPI(RegOpMode,kSleepMode);

#ifdef RADIOMODE_LORA
	// Now put the radio in LoRa mode
	RadioSleepMode();

	// and go to standby mode
	RadioStandbyMode();
	// 7 6 5 4 3 2 1 0
	// | | | | | | | |_____ (0) LDR Optimization 1=enabled, 0= disabled
	// | | | | | | |_______ (1) RxPayloadCrcOn
	// | | | | | |_________ (0) IHModeOn = 1
	// | | |_|_|___________ (001) CR (=4/(4+CR))
	// |_|_________________ (10) BW 00= 125khz, 01=250khzm=, 10=500khz, 11=reserved
	//
	// BW=500kHz, CR=4/5, IH=off, CRC=on, LDR Optimize = off
	WriteCHARSPI(RegLoraModemConfig1,0x8a);

	// 7 6 5 4 3 2 1 0
	// | | | | | | |_|_____ (00) SymbTimeout (9:8)
	// | | | | | |_________ (1) AgcAutoOn
	// | | | | |___________ (0) TxContinuousMode
	// |_|_|_|_____________ (1001) SF (9)
	//
	WriteCHARSPI(RegLoraModemConfig2,0x94);
	// magic number from Semtech's sample code.  No idea what this does
	// TODO:  Verify that this magic number is required.
	WriteCHARSPI(0x31, 0x43);
	// the radio doesn't work without this.  Get CRC errors or nothing without it.  Found it by complete accident
	WriteCHARSPI(0x2b,0x11);
#endif
	// Set channel to middle of band
	RadioSetChannel(0);

	// Lowest power level, all PA off
	WriteCHARSPI(RegPaConfig,0x8f);
	// enable +20dBm
	WriteCHARSPI(RegPaDac,0x84);

	// LNA is 50 ohms and manually set to highest gain
	WriteCHARSPI(RegLna,0x00);
	// Setup DIO pins for standby/sleep/fs mode
	// dio0 = TempChange/LowBat, dio1 = FifoLevel, dio2=FifoFull, dio3=FifoEmpty, dio4=PLLLock, dio5=ModeReady, CLKOUT = off
	WriteCHARSPI(RegDioMapping1, 0xc0);
	WriteCHARSPI(RegDioMapping2, 0x70);

	ClearFIFO();
	return 1;
}
void RadioSetPreambleCount(UU16 preambleCount)
{
	WriteCHARSPI(RegLoraPreambleMsb,preambleCount.U8[1]);
	WriteCHARSPI(RegLoraPreambleLsb,preambleCount.U8[0]);
}

/// U8 StandbyMode()
///
/// Parameters:
/// none
///
/// Description:
/// Puts the radio into the IDLE_STBY state, the lowest power state where the radio can still generate interrupts.  Interrupts are enabled on exit.
///
/// Results:
/// Always returns kSuccess
void RadioStandbyMode(void)
{
#ifdef RADIOMODE_LORA
	WriteCHARSPI(RegOpMode, kStandbyMode);
	// Setup DIO pins for standby/sleep/fs mode
	// dio0 = TempChange/LowBat, dio1 = FifoLevel, dio2=FifoFull, dio3=FifoEmpty, dio4=PLLLock, dio5=ModeReady, CLKOUT = off
	//WriteCHARSPI(RegDioMapping1, 0xc0);
	//WriteCHARSPI(RegDioMapping2, 0x70);
	_operatingMode = kStandbyMode;
#endif
}
void RadioSleepMode()
{
#ifdef RADIOMODE_LORA
	WriteCHARSPI(RegOpMode, kSleepMode | kLoraMode);
	// Setup DIO pins for standby/sleep/fs mode
	// dio0 = TempChange/LowBat, dio1 = FifoLevel, dio2=FifoFull, dio3=FifoEmpty, dio4=PLLLock, dio5=ModeReady, CLKOUT = off
	//WriteCHARSPI(RegDioMapping1, 0xc0);
	//WriteCHARSPI(RegDioMapping2, 0x70);
	_operatingMode = kSleepMode;
#endif
}/// U8 SetChannel(U8 Channel)
///
/// Parameters:
/// channel, U8, Valid channels are 0-25
///
/// Description;
/// Sets the radio channel. Valid channels are 0-25, channel 0=902.5MHz, channel spacing=1MHz
///
/// Returns:
/// kSuccess if everything is OK
/// kInvalidValueError if the channel number is invalid
void RadioSetChannel(U8 channel)
{
	UU32 frf;

	// Fstep = Fxosc / 2^19 => 32Mhz/2^19 = 61
	// Fc = Fstep * RegFrf[23:0]
	// => RegFrf = Fc / Fstep
	// Fc = 902.5MHz + channel * .5Mhz
	// => RegFrf = (902500000 + channel*500000) / 61.035
	frf.U32 = (14786560+(U32)channel*(U32)8192) ;

	WriteCHARSPI(RegFrfMsb, frf.U8[2]);
	WriteCHARSPI(RegFrfMid, frf.U8[1]);
	WriteCHARSPI(RegFrfLsb, frf.U8[0]);
	//ReadRegs();
}
/// U8 SetTxPower(U8 power)
///
/// Parameters:
/// power,U8,Power setting.  Varies based on chip. Masked with 0x07 prior to writing.
///
/// Description:
/// Set the transmitter output power.  Does not put the chip in TX mode, it just sets the TX power.
///
/// power		Power
/// =====		==========
/// 0-15		invalid
/// 16			+5 dBm
/// 17			+6 dBm
/// 18			+7 dBm
/// 19			+8 dBm
/// 20			+9 dBm
/// 21			+10 dBm
/// 22			+11 dBm
/// 23			+12 dBm
/// 24			+13 dBm
/// 25			+14 dBm
/// 26			+15 dBm
/// 27			+16 dBm
/// 28			+17 dBm
/// 29			+18 dBm
/// 30			+19 dBm
/// 31			+20 dBm
///
///
///
/// Returns:
/// Always returns kSuccess
void RadioSetTxPower(U8 power)
{
	WriteCHARSPI(RegPaConfig,0x80 | (power&0x0f));
	// enable +20dBm
	WriteCHARSPI(RegPaDac,0x84);
}

/// U8 ReadRSSIValue()
///
/// Parameters:
/// none
///
/// Description:
/// Returns RSSI value.
///
/// Returns:
/// RSSI value
U8 RadioGetRSSI()
{
 	return ReadCHARSPI(RegLoraPktRssiValue);
}
U8 RadioGetSNR()
{
	return ReadCHARSPI(RegLoraPktSnrValue);
}
/// MethodResult SetMACAddress(UU32 macAddress)
///
/// Parameters:
/// macAddress,UU32,local MAC Address
///
/// Description:
/// Set the RX check header to the mac address and enable checking on all 4 header bytes.  This will filter incoming messages
/// to out address or 0xFFFFFFFF which is the broadcast address
void RadioSetMACAddress(UU32 macAddress)
{
	// todo: SetMACAddress() RadioAPI
}

S8 RadioGetTemperature()
{
	// todo: GetTemperature() RadioAPI
	return 0;
}
void RadioSetEncryptionKey(UU256 key)
{
	int i;
	// todo: SetEncryptionKey() RadioAPI
}
/*
U8 GetRadioState()
{
	U8 om;

	om = ReadCHARSPI(RegOpMode);
	om=om&0x07;
	return om;
}*/
U8 RadioIsIdle()
{
	U8 om;

	om = ReadCHARSPI(RegOpMode);
	om=om&0x07;
	// if we are in standby, we are idle
	if(om==1) return 1;
	// if we are in sleep, we are idle.
	if(om==0) return 1;
	return 0;
}
/*
U8 GetRFICFlags()
{
	return ReadCHARSPI(RegLoraIrqFlags);
}
*/

